#include "serialdebuggingassistant.h"
#include "ui_serialdebuggingassistant.h"


const QString PortIni_0 = "portName";
const QString PortIni_1 = "baudRate";
const QString PortIni_2 = "parity";
const QString PortIni_3 = "dataBits";
const QString PortIni_4 = "stopBits";

const QString RxIni_0 = "ReceivingSteeringFile";
const QString RxIni_1 = "AutoWrapDisplay";
const QString RxIni_2 = "DisplayReceivingTime";
const QString RxIni_3 = "ItIsInHexadecimalFormat";
const QString RxIni_4 = "PauseReceivingDisplay";

const QString TxIni_0 =  "EnablingFileDataSource";
const QString TxIni_1 =  "AutomaticallySendsAdditionalBits";
const QString TxIni_2 =  "ItClearsAutomaticallyAfterSending";
const QString TxIni_3 =  "SendInHexadecimalFormat";
const QString TxIni_4 =  "TheDataStreamIsSentInALoop";
const QString TxIni_5 =  "CyclicTransmissionTime";


SerialDebuggingAssistant::SerialDebuggingAssistant(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::SerialDebuggingAssistant)
    ,m_port(new QSerialPort(this))
    ,m_settings(QDir::currentPath()+"/config.ini",QSettings::IniFormat)
    ,m_txNum(0)
    ,m_rxNum(0)
{
    ui->setupUi(this);
    Init();

    //    QString fileName;
    //    fileName = ":/Images/electrical-32.png";
    //    if(!fileName.isEmpty()){ //判断文件名是否为空
    //        QString saveName = QFileDialog::getSaveFileName(this,tr("Save File"),".",tr("Images (*.ico);;Images (*.icon)"));
    //        qDebug() << "saveName=" << saveName;
    //        if(!saveName.isEmpty()){
    //            QPixmap map(fileName);
    //            QPixmap newMap =  map.scaled(32,32);
    //            newMap.save(saveName);
    //        }
    //    }
}

SerialDebuggingAssistant::~SerialDebuggingAssistant()
{
    if(m_port->isOpen())
    {
        m_port->close();
    }
    delete m_port;
    delete m_tableWidget;
    delete ui;
}

void SerialDebuggingAssistant::Init()
{
    QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    foreach (QSerialPortInfo port, ports) {
        ui->cBox_port->addItem(port.portName());
    }

    m_baudRateEnum  = QMetaEnum::fromType<QSerialPort::BaudRate>();
    m_parityEnum    = QMetaEnum::fromType<QSerialPort::Parity>();
    m_dataBitsEnum  = QMetaEnum::fromType<QSerialPort::DataBits>();
    m_stopBitsEnum  = QMetaEnum::fromType<QSerialPort::StopBits>();
    for (int i = 0;i<m_baudRateEnum.keyCount()-1;i++)
    {
        ui->cBox_baudRate->addItem(m_baudRateEnum.key(i));
    }
    for (int i = 0;i<m_parityEnum.keyCount()-1;i++)
    {
        ui->cBox_parity->addItem(m_parityEnum.key(i));
    }
    for (int i = 0;i<m_dataBitsEnum.keyCount()-1;i++)
    {
        ui->cBox_dataBits->addItem(m_dataBitsEnum.key(i));
    }
    for (int i = 0;i<m_stopBitsEnum.keyCount()-1;i++)
    {
        ui->cBox_stopBits->addItem(m_stopBitsEnum.key(i));
    }

    //设置默认
    ui->cBox_port->setCurrentText(m_settings.value(PortIni_0).toString());
    ui->cBox_baudRate->setCurrentText(m_settings.value(PortIni_1).toString());
    ui->cBox_parity->setCurrentText(m_settings.value(PortIni_2).toString());
    ui->cBox_dataBits->setCurrentText(m_settings.value(PortIni_3).toString());
    ui->cBox_stopBits->setCurrentText(m_settings.value(PortIni_4).toString());


    //ui->cBox_turnOverFile->setChecked(m_settings.value(RxIni_0).toBool());
    ui->cBox_0x0A0x0D->setChecked(m_settings.value(RxIni_1).toBool());
    ui->cBox_timeStamp->setChecked(m_settings.value(RxIni_2).toBool());
    ui->cBox_rxHex->setChecked(m_settings.value(RxIni_3).toBool());
    ui->cBox_stopDisplay->setChecked(m_settings.value(RxIni_4).toBool());

    //ui->cBox_dataSrc->setChecked(m_settings.value(TxIni_0).toBool());
    ui->cBox_add->setChecked(m_settings.value(TxIni_1).toBool());
    ui->cBox_clear->setChecked(m_settings.value(TxIni_2).toBool());
    ui->cBox_txHex->setChecked(m_settings.value(TxIni_3).toBool());
    ui->cBox_cycle->setChecked(m_settings.value(TxIni_4).toBool());

    ui->lEdt_cycleTime->setText(m_settings.value(TxIni_5).toString());
    ui->actionAboutQt->setIcon(QApplication::style()->standardIcon(QStyle::SP_TitleBarMenuButton));


    m_txNumText = new QLabel(this);
    m_rxNumText = new QLabel(this);
    m_resetCount = new QPushButton(QIcon(":/Images/icons8_reset.ico"),"复位计数",this);
    ui->statusbar->addWidget(m_txNumText);
    ui->statusbar->addWidget(m_rxNumText);
    ui->statusbar->addWidget(m_resetCount);
    UpdataUiRxNum();
    UpdataUiTxNum();
    connect(m_resetCount,&QPushButton::clicked,[=]()
    {
        m_rxNum = 0;
        m_txNum = 0;
        UpdataUiRxNum();
        UpdataUiTxNum();
    });

    if(m_settings.value(TxIni_3).toBool())
    {
        QString text = ui->pEdt_Tx->toPlainText().toLocal8Bit().toHex(' ').toUpper();
        ui->pEdt_Tx->clear();
        ui->pEdt_Tx->setPlainText(text);
    }

    connect(m_port,&QSerialPort::readyRead,[=]()
    {
        if(ui->cBox_turnOverFile->isChecked())
        {
            QFile file(m_savePath);
            if(file.open(QFile::WriteOnly|QFile::Text|QFile::Append))
            {
                QByteArray data = m_port->readAll();
                file.write(data);
                m_rxNum+=data.length();
                UpdataUiRxNum();
                file.close();
            }else
            {
                InputDisplay(file.errorString());
            }
        }
        else
        {
            QByteArray data = m_port->readAll();
            InputDisplay(data);
            m_rxNum+=data.length();
            UpdataUiRxNum();
        }

    });

    m_timer = new QTimer(this);
    connect(m_timer,&QTimer::timeout,[=]()
    {
        WriteData();
    });

    m_tableWidget = new QTableWidget();
    m_tableWidget->setWindowTitle("附加位");
    m_tableWidget->setRowCount(100);
    m_tableWidget->setColumnCount(1);
    m_tableWidget->setHorizontalHeaderLabels(QStringList()<<"data");
    m_tableWidget->resize(600,500);
    for (int i =0;i<m_tableWidget->rowCount();i++)
    {
        QTableWidgetItem *item = new QTableWidgetItem();
        item->setFlags(Qt::ItemIsEnabled|Qt::ItemIsEditable|Qt::ItemIsUserCheckable);
        item->setCheckState(Qt::Unchecked);
        m_tableWidget->setItem(i,0,item);
        m_tableWidget->setColumnWidth(i,m_tableWidget->size().width()-50);
        //m_listWidget->openPersistentEditor(item);
    }

}

void SerialDebuggingAssistant::InputDisplay(QString text, bool isData, bool isTx)
{

    if(ui->cBox_stopDisplay->checkState() == Qt::Checked)return;
    if(ui->cBox_timeStamp->checkState() == Qt::Checked && isData == true)
    {
        if(isTx)
        {

            text.prepend(QDateTime::currentDateTime().toString("发送: yyyy-MM-dd hh:mm:ss.zzz \r\n"));
        }
        else
        {
            text.prepend(QDateTime::currentDateTime().toString("接收: yyyy-MM-dd hh:mm:ss.zzz \r\n"));
        }

    }
    if(ui->cBox_0x0A0x0D->checkState() == Qt::Checked)
    {
        if(isTx)
        {
            QTextCharFormat fmt;
            fmt.setForeground(QBrush("green"));
            ui->pEdt_Rx->mergeCurrentCharFormat(fmt);
        }
        else
        {
            QTextCharFormat fmt;
            fmt.setForeground(QBrush("blue"));
            ui->pEdt_Rx->mergeCurrentCharFormat(fmt);
        }
        ui->pEdt_Rx->appendPlainText(text.append("\r\n"));
    }
    else
    {
        if(isTx)
        {
            QTextCharFormat fmt;
            fmt.setForeground(QBrush("green"));
            ui->pEdt_Rx->mergeCurrentCharFormat(fmt);
        }
        else
        {
            QTextCharFormat fmt;
            fmt.setForeground(QBrush("blue"));
            ui->pEdt_Rx->mergeCurrentCharFormat(fmt);
        }
        ui->pEdt_Rx->insertPlainText(text.remove("\r\n"));
    }
}

void SerialDebuggingAssistant::InputDisplay(QByteArray data)
{

    if(data.right(2) == "\r\n")
    {
        data = QByteArray(data.data(),data.length()-2);
    }
    if(ui->cBox_rxHex->checkState() == Qt::Checked)
    {
        QString temp = QString(data.toHex(' ').data());

        temp = temp.toUpper();
        InputDisplay(temp,true);
    }
    else
    {
        InputDisplay(QString::fromLocal8Bit(data),true);
    }

}

void SerialDebuggingAssistant::WriteData()
{
    if(ui->cBox_dataSrc->isChecked())
    {
        QFile file(m_txDataSrcPath);
        if(file.open(QFile::ReadOnly|QFile::Text))
        {
            QByteArray data;
            data = file.readAll();
            file.close();
            m_port->write(data);
            InputDisplay(QString::fromLocal8Bit(data),true,true);
            m_txNum += data.length();
            UpdataUiTxNum();
        }else
        {
            InputDisplay(file.errorString().toLocal8Bit());
        }
    }else
    {
        if(ui->cBox_txHex->checkState() == Qt::Checked)
        {

            QString text =ui->pEdt_Tx->toPlainText();
            m_port->write(QByteArray::fromHex(text.toStdString().c_str()).append("\r\n"));
            InputDisplay(ui->pEdt_Tx->toPlainText(),true,true);
            m_txNum += QByteArray::fromHex(text.toStdString().c_str()).append("\r\n").length();
            qDebug()<<m_txNum;
            UpdataUiTxNum();
        }
        else
        {
            m_port->write(ui->pEdt_Tx->toPlainText().toLocal8Bit().append("\r\n"));
            InputDisplay(ui->pEdt_Tx->toPlainText(),true,true);
            m_txNum += ui->pEdt_Tx->toPlainText().toLocal8Bit().append("\r\n").length();
            UpdataUiTxNum();

        }
        if(ui->cBox_clear->checkState() == Qt::Checked)
        {
            ui->pEdt_Tx->clear();
        }
    }

}

void SerialDebuggingAssistant::UpdataUiTxNum()
{
    m_rxNumText->setText("Tx:"+QString::number(m_txNum));
}

void SerialDebuggingAssistant::UpdataUiRxNum()
{
    m_txNumText->setText("Rx:"+QString::number(m_rxNum));
}


void SerialDebuggingAssistant::on_pBtn_open_clicked()
{
    m_port->setPortName(ui->cBox_port->currentText());
    m_port->setBaudRate(m_baudRateEnum.keyToValue(ui->cBox_baudRate->currentText().toStdString().c_str()));


    switch (ui->cBox_parity->currentIndex()) {
    case 0:
        m_port->setParity(QSerialPort::NoParity);
        break;
    case 1:
        m_port->setParity(QSerialPort::EvenParity);
        break;
    case 2:
        m_port->setParity(QSerialPort::OddParity);
        break;
    case 3:
        m_port->setParity(QSerialPort::SpaceParity);
        break;
    case 4:
        m_port->setParity(QSerialPort::MarkParity);
        break;
    default:
        m_port->setParity(QSerialPort::UnknownParity);
        break;
    }

    switch (ui->cBox_dataBits->currentIndex()) {
    case 0:
        m_port->setDataBits(QSerialPort::Data5);
        break;
    case 1:
        m_port->setDataBits(QSerialPort::Data6);
        break;
    case 2:
        m_port->setDataBits(QSerialPort::Data7);
        break;
    case 3:
        m_port->setDataBits(QSerialPort::Data8);
        break;
    default:
        m_port->setDataBits(QSerialPort::UnknownDataBits);
        break;
    }

    switch (ui->cBox_stopBits->currentIndex()) {
    case 0:
        m_port->setStopBits(QSerialPort::OneStop);
        break;
    case 1:
        m_port->setStopBits(QSerialPort::OneAndHalfStop);
        break;
    case 2:
        m_port->setStopBits(QSerialPort::TwoStop);
        break;
    default:
        m_port->setStopBits(QSerialPort::UnknownStopBits);
        break;
    }

    if(ui->pBtn_open->text() == "打开串口")
    {
        m_port->open(QIODevice::ReadWrite);
        if(m_port->error() == QSerialPort::NoError)
        {
            ui->pBtn_open->setText("关闭串口");
            InputDisplay(QString("串口打开成功"));
            ui->cBox_port->setEnabled(false);
            ui->cBox_baudRate->setEnabled(false);
            ui->cBox_parity->setEnabled(false);
            ui->cBox_dataBits->setEnabled(false);
            ui->cBox_stopBits->setEnabled(false);
            ui->pBtn_open->setIcon(QIcon(":/Images/icons8_connected.ico"));
        }
        else
        {
            qDebug()<<m_port->error();
        }
    }
    else
    {
        m_port->close();
        ui->pBtn_open->setText("打开串口");
        InputDisplay(QString("串口关闭成功"));
        ui->cBox_port->setEnabled(true);
        ui->cBox_baudRate->setEnabled(true);
        ui->cBox_parity->setEnabled(true);
        ui->cBox_dataBits->setEnabled(true);
        ui->cBox_stopBits->setEnabled(true);
        ui->pBtn_open->setIcon(QIcon(":/Images/icons8_disconnected.ico"));
    }
}

void SerialDebuggingAssistant::on_pBtn_send_clicked()
{
    if(!m_port->isOpen())
    {
        InputDisplay(QString("串口未打开"));
        return;
    }

    if(ui->cBox_cycle->checkState() == Qt::Checked)
    {
        if(ui->pBtn_send->text() == "发送")
        {
            m_timer->setInterval(ui->lEdt_cycleTime->text().toInt(nullptr,10));
            m_timer->start();
            ui->pBtn_send->setText("停止");
            ui->cBox_cycle->setEnabled(false);
            ui->lEdt_cycleTime->setEnabled(false);
            ui->pBtn_send->setIcon(QIcon(":/Images/icons8_stop.ico"));
        }
        else
        {
            m_timer->stop();
            ui->pBtn_send->setText("发送");
            ui->cBox_cycle->setEnabled(true);
            ui->lEdt_cycleTime->setEnabled(true);
            ui->pBtn_send->setIcon(QIcon(":/Images/icons8_email_send.ico"));
        }
    }
    else
    {
        WriteData();
    }
}

void SerialDebuggingAssistant::on_cBox_turnOverFile_clicked(bool checked)
{
    //m_settings.setValue(RxIni_0,QVariant(checked));
    if(checked)
    {
        m_savePath.append(QDir::currentPath());
        m_savePath.append("/");
        m_savePath.append(QDate::currentDate().toString("yyyy_MM_dd recive.txt"));
        QMessageBox::information(
                    this,
                    "保存文件",
                    QString("文件保存路径:%1")
                    .arg(m_savePath)
                    );
    }
}

void SerialDebuggingAssistant::on_cBox_0x0A0x0D_clicked(bool checked)
{
    m_settings.setValue(RxIni_1,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_timeStamp_clicked(bool checked)
{
    m_settings.setValue(RxIni_2,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_rxHex_clicked(bool checked)
{
    m_settings.setValue(RxIni_3,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_stopDisplay_clicked(bool checked)
{
    m_settings.setValue(RxIni_4,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_dataSrc_clicked(bool checked)
{
    //m_settings.setValue(TxIni_0,QVariant(checked));
    if(checked)
    {
        m_txDataSrcPath = QFileDialog::getOpenFileName(this,"启用文件数据源",QDir::currentPath(),"All(*.*)TXT(*.txt)");
        if(m_txDataSrcPath.isEmpty())
        {
            QMessageBox::warning(this,"启用文件数据源","文件路径为空");
            ui->cBox_dataSrc->setChecked(false);
        }
    }

}

void SerialDebuggingAssistant::on_cBox_add_clicked(bool checked)
{
   // m_settings.setValue(TxIni_1,QVariant(checked));
    if(checked)
    {
        m_tableWidget->show();
    }
}

void SerialDebuggingAssistant::on_cBox_clear_clicked(bool checked)
{
    m_settings.setValue(TxIni_2,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_txHex_clicked(bool checked)
{
    m_settings.setValue(TxIni_3,QVariant(checked));

    if(checked)
    {
        QString text = ui->pEdt_Tx->toPlainText().toLocal8Bit().toHex(' ').toUpper();
        ui->pEdt_Tx->clear();
        ui->pEdt_Tx->setPlainText(text);
    }
    else
    {
        QString text =ui->pEdt_Tx->toPlainText();
        text = QString::fromLocal8Bit(QByteArray::fromHex(text.toStdString().c_str()));
        ui->pEdt_Tx->clear();
        ui->pEdt_Tx->setPlainText(text);
    }
}

void SerialDebuggingAssistant::on_cBox_cycle_clicked(bool checked)
{
    m_settings.setValue(TxIni_4,QVariant(checked));
}

void SerialDebuggingAssistant::on_cBox_port_activated(const QString &arg1)
{
    m_settings.setValue(PortIni_0,QVariant(arg1));
}

void SerialDebuggingAssistant::on_cBox_baudRate_activated(const QString &arg1)
{
    m_settings.setValue(PortIni_1,QVariant(arg1));
}

void SerialDebuggingAssistant::on_cBox_parity_activated(const QString &arg1)
{
    m_settings.setValue(PortIni_2,QVariant(arg1));
}

void SerialDebuggingAssistant::on_cBox_dataBits_activated(const QString &arg1)
{
    m_settings.setValue(PortIni_3,QVariant(arg1));
}

void SerialDebuggingAssistant::on_cBox_stopBits_activated(const QString &arg1)
{
    m_settings.setValue(PortIni_4,QVariant(arg1));
}

void SerialDebuggingAssistant::on_lEdt_cycleTime_editingFinished()
{
    m_settings.setValue(TxIni_5,QVariant(ui->lEdt_cycleTime->text()));
}

void SerialDebuggingAssistant::on_actionExit_triggered()
{
    exit(0);
}

void SerialDebuggingAssistant::on_actionAbout_triggered()
{
    QMessageBox::about(this,"关于串口调试助手",
                       "<p><a href=\"https://blog.csdn.net/qq_42815643?type=blog\">CSDN:努力向前爬的蜗牛</p>"
                       "<p><a href=\"https://github.com/danqingpro\">github:danqingpro</p>"
                       "<p><a href=\"https://gitee.com/danqpro\">gitee:danqpro</p>"
                       );
}

void SerialDebuggingAssistant::on_actionAboutQt_triggered()
{
    //QMessageBox::aboutQt(this,"关于QT");
    QApplication::aboutQt();
}

void SerialDebuggingAssistant::on_actionOpenFile_triggered()
{
    QString path = QFileDialog::getOpenFileName(this,"打开文件",QDir::currentPath(),"All(*.*)TXT(*.txt)");
    QFile file(path);
    if(file.open(QFile::ReadOnly|QFile::Text))
    {
        QByteArray data;
        data = file.readAll();
        file.close();
        InputDisplay(data);
    }
    else
    {
        InputDisplay(file.errorString().toLocal8Bit());
    }
}



void SerialDebuggingAssistant::on_pBtn_save_clicked()
{
//    if(m_port->isOpen())
//    {
//        on_pBtn_open_clicked();
//    }
    QString savePath = QFileDialog::getSaveFileName(this,"保存文件",QDir::currentPath(),"All(*.*)TXT(*.txt)");
    QFile file(savePath);
    if(file.open(QFile::WriteOnly|QFile::Text))
    {
        file.write(ui->pEdt_Rx->toPlainText().toLocal8Bit());
        file.close();
    }

}

void SerialDebuggingAssistant::on_pBtn_loadFile_clicked()
{
    on_actionOpenFile_triggered();
}
